
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>

#include "FileParser.hpp"

FileParser::FileParser(Puzzle& puzzle) :
        _puzzle(puzzle),
        _nbLine(0),
        _lineSize(-1)
{

}

FileParser::~FileParser()
{

}

bool FileParser::parse(const std::string & path)
{
    char line[64];
    std::string sline;
    std::ifstream file(path.c_str());
    bool flag = true;
    if (file.is_open())
    {
        while (!file.eof())
        {
            memset(line, 0 , 64);
            file.getline(line, 64, '\n');
            sline = line;
            if (sline.size() > 0)
            {
                if (!this->_isCommentLine(sline))
                {
                    if (this->_nbLine == 0 || this->_nbLine < this->_lineSize)
                    {
                        if (flag)
                            flag = false;
                        else if (this->_addLine(sline))
                            this->_nbLine++;
                    } else {
                        std::cerr << "Too much lines, puzzle must be a square" << std::endl;
                        return false;
                    }
                }
            }
        }
        file.close();
        if (!this->_isValide())
        {
            std::cerr << "Invalid puzzle numbers" << std::endl;
            return false;
        }
        return true;
    } else
        std::cerr << "Could'nt open file: " << path << std::endl;
    return false;
}

bool FileParser::_isCommentLine(std::string const & line) const
{
    for (unsigned int i = 0; i < line.size(); i++)
    {
        if (line[i] != ' ' && line[i] != '\t')
        {
            if (line[i] == '#')
                return true;
            else
                return false;
        }
    }
    return false;
}

bool FileParser::_addLine(std::string const & line)
{
    std::stringstream ss;
    int value;
    Coord c;
    c.y = this->_nbLine;

    int lineSize = this->_getLineSize(line);
    if (this->_nbLine == 0)
    {
        this->_lineSize = lineSize;
        this->_puzzle.create(this->_lineSize);
    }
    else if (lineSize != this->_lineSize)
    {
        std::cerr << "Wrong length at line " << this->_nbLine + 1 << ": " << lineSize << " instead of " << this->_lineSize << std::endl;
        return false;
    }
    ss << line;
    for (c.x = 0; c.x < this->_lineSize; c.x++)
    {
        ss >> value;
        if (ss.fail())
        {
            std::cerr << "Wrong value in puzzle file" << std::endl;
            return false;
        }
        this->_puzzle.setAt(c, value);
        this->_addedValues.insert(value);
    }
    return true;
}

unsigned int FileParser::_getLineSize(const std::string &line)
{
    unsigned int a;
    std::stringstream ss;
    unsigned int size = 0;

    ss << line;
    ss >> a;
    while (!ss.fail())
    {
        ss >> a;
        size++;
    }
    return size;
}

bool FileParser::_isValide() const
{
    int max = this->_lineSize * this->_lineSize;
    for (int i = 0; i < max; i++)
    {
        auto it = this->_addedValues.find(i);
        if (it == this->_addedValues.end())
            return false;
    }
    return true;
}

